本來前端應該要更早點講的,不過 Flask 的前端有了傳入的值的話,可以有更多的操作,所以就放到這邊才講了。
Flask 的前端是由 Jinja2 樣版引擎來處理,而樣板引擎可以像是程式語言一樣對參數進行各種處裡。
首先,前端的頁面預設是放在專案根目錄下的 templates
(有 s
,可以改位置,但下一篇靜態檔案時再說),就像這樣:
ithome/
├── templates
│ └── index.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
既然這篇主題是前端,那麼先把跟主題無關的後端部分快速講完。後端要傳回頁面是使用 render_template()
這個 function,這個 function 第一個參數必須是一個頁面的檔案;後面跟著要傳入頁面的參數,使用 key-value 傳入,value 可以是 dict 、 list 或一般的變數。就像這樣:
app.py
@app.route('/')
def index():
return render_template('index.html')
# or
return render_template('index.html', username='<username>')
# or
return render_template('index.html', username=['A', 'B', 'C'])
# or
return render_template('index.html', username={'Users': ['A', 'B', 'C'])
後端要傳回頁面大概可以用這幾種方式,不一定只能有一個 key-value ,也可以有多個(中間皆使用逗點分開)。
接著就要來說道前端頁面的部份了,剛剛講到樣板引擎可以像程式語言一樣對參數進行處理,甚至進行各種條件判斷。說到這些,想當然的一定有 if-else 跟 for 了吧。
Jinja2 樣板引擎可以處裡 .html
檔(雖然可以處裡的不只 .html
就是了),在 Jinja2 除了可以解析普通的 HTML 語法,還有兩種特殊的標籤:{{ }}
跟 {% %}
。{{ }}
是使用在渲染到頁面上的標籤;{% %}
是使用在各種判斷以及迴圈使用的標籤。需要注意的大概就這樣而已,接著實際操作一次會更加清晰。
第一個是最常用的 if-elif-else,實際來看一下前後端如何實作吧:
app.py
@app.route('/')
def index():
return render_template('index.html')
@app.route('/<username>')
def user_home(username):
return render_template('index.html', username=escape(username))
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>template value</title>
</head>
<body>
<div>
{% if username %}
<h1>Welcome {{ username }}</h1>
{% else %}
<h1>Hello</h1>
{% endif %}
</div>
</body>
</html>
這樣就可以再有輸入使用者名稱的時候,會自動顯示出不同的頁面。像這樣:
http://localhost:5000/
http://localhost:5000/User
第二個也是很常使用的 for,這邊也直接來看如何實作吧:
app.py
@app.route('/')
def index():
return render_template('index.html')
@app.route('/<username>')
def user_home(username):
return render_template('index.html', username=escape(username))
@app.route('/<int:time>')
def user_list_home(time): # 真的不知道要取什麼名字了
users = []
for i in range(time):
users.append("user" + str(i))
return render_template('index.html', users=users)
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>template value</title>
</head>
<body>
<div>
{% if username %}
<h1>Welcome {{ username }}</h1>
{% elif users %}
{% for username in users %}
<h1>Welcome {{ username }}</h1>
{% endfor %}
{% else %}
<h1>Hello</h1>
{% endif %}
</div>
</body>
</html>
基本上只是根據前一個小改而已,所以輸入前面那兩個 URL 也會出現一樣的結果,不一樣的只有這個:
http://localhost:5000/5
常用的邏輯控制大概就這樣,接著要講不太一樣的東西。
如果現在要做多個畫面,四周都差不多,只有中間內容不太一樣(就像這篇跟上一篇一樣,只有中間內容不一樣),這時有兩個方法可以解決。第一個想到的就是萬能的 ctrl + c
& ctrl + v
對吧,真的很好用我知道,但是有點太慢了。第二個就是這個 extends
跟 block
。
那這個要怎麼用呢?讓我們先打架構改成這樣,再根據上面的程式小改一下。
ithome
├── templates
│ ├── res # 先隨便取個名字,不用做資料夾也行。
│ │ └── home.html # 它跟 base.html 同一層也可以
│ ├── base.html
│ └── index.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
app.py
@app.route('/')
def index():
return render_template('index.html')
@app.route('/<username>')
def user_home(username):
return render_template('res/home.html', username=escape(username))
@app.route('/<int:time>')
def user_list_home(time): # 真的不知道要取什麼名字了
users = []
for i in range(time):
users.append("user" + str(i))
return render_template('res/home.html', users=users)
base.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<div>
{% block content %}
{% endblock %}
</div>
</body>
</html>
index.html
{% extends 'base.html' %}
{% block title %}
Index
{% endblock %}
{% block content %}
<h1>Hello</h1>
{% endblock %}
home.html
{% extends 'base.html' %}
{% block title %}
Home
{% endblock %}
{% block content %}
{% if username %}
<h1>Welcome {{ username }}</h1>
{% elif users %}
{% for username in users %}
<h1>Welcome {{ username }}</h1>
{% endfor %}
{% else %}
<a href={{ url_for('index') }}><button>Index</button></a>
{% endif %}
{% endblock %}
改好之後,輸入上面的三個 URL 的話,應該會得到一樣的結果(廢話,因為只是把它們拆開而已)。
看到這裡,也大概知道它是如何運作的了吧!就是同樣的東西共享,在需要填入不同東西的地方挖個洞、取個名字(名子隨便取,但是盡量取有意義的名字),然後在子頁面繼承之後,輸入名字與要填入的東西,就可以達成這樣的效果。
那麼就大概這樣,這邊只有 HTML 相關的東西,有關 CSS 與 JavaScript 的東西,以及想要改位置的方式下一篇會講到。
大家掰~掰~